package org.suyafei.cotroller;

import com.alibaba.fastjson.JSONObject;
import com.wechat.pay.contrib.apache.httpclient.auth.ScheduledUpdateCertificatesVerifier;
import com.wechat.pay.contrib.apache.httpclient.util.AesUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.suyafei.config.WeChatPayConfig;
import org.suyafei.enums.ProductOrderPayTypeEnum;
import org.suyafei.service.ProductOrderService;

import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @author 宿某人
 * @Date: 2022/03/07/15:02
 * @Description:
 */
@Controller
@RequestMapping("/api/callback/order/v1/")
@Slf4j
public class PayCallbackController {

    @Autowired
    private WeChatPayConfig weChatPayConfig;

    @Autowired
    private ProductOrderService productOrderService;

    @Autowired
    private ScheduledUpdateCertificatesVerifier verifier;

    /**
     * 获取报文
     * <p>
     * 验证签名
     * <p>
     * 解密
     * <p>
     * 处理业务逻辑
     * <p>
     * 响应需求
     *
     * @param response
     * @return
     */
    @RequestMapping("wechat")
    @ResponseBody
    public Map<String, String> wechatPayCallback(HttpServletResponse response, HttpServletRequest request) {


        String requestBody = getRequestBody(request);
        //随机串
        String nonceStr = request.getHeader("Wechatpay-Nonce");

        //签名
        String signature = request.getHeader("Wechatpay-Signature");

        //证书序列号
        String serialNo = request.getHeader("Wechatpay-Serial");

        //时间搓
        String timestamp = request.getHeader("Wechatpay-Timestamp");

        //构造签名串
        String signStr = Stream.of(timestamp, nonceStr, requestBody).collect(Collectors.joining("\n", "", "\n"));

        Map<String, String> map = new HashMap<>();
        try {
            //验证签名
            boolean result = verifiedSign(serialNo, signStr, signature);

            if (result) {
                //解密数据
                String plainBody = decryptBody(requestBody);
                log.info("解密后的铭文:{}", plainBody);

                Map<String ,String> paramsMap = convertWechatPayMsgToMap(plainBody);
                //处理业务逻辑
                productOrderService.processOrderCallbackMsg(ProductOrderPayTypeEnum.WECHAT_PAY, paramsMap);
                //响应微信
                map.put("code", "SUCCESS");
                map.put("message", "成功");
            }

        } catch (Exception e) {
            log.error("微信支付回调异常:{}", e);
        }
        return map;

    }

    /**
     * 把body转换为map
     * @param plainBody
     * @return
     */
    private Map<String, String> convertWechatPayMsgToMap(String plainBody) {
        Map<String, String> paramsMap = new HashMap<>();

        JSONObject jsonObject = JSONObject.parseObject(plainBody);
        //用户订单
        paramsMap.put("out_trade_no",jsonObject.getString("out_trade_no"));
        //交易状态
        paramsMap.put("trade_state", jsonObject.getString("trade_state"));
        //附加数据
        paramsMap.put("account_no", jsonObject.getJSONObject("attach").getString("account_no"));

        return paramsMap;
    }

    private String decryptBody(String body) throws GeneralSecurityException {
        AesUtil aesUtil = new AesUtil(weChatPayConfig.getApiV3Key().getBytes(StandardCharsets.UTF_8));
        JSONObject jsonObject = JSONObject.parseObject(body);
        JSONObject resource = jsonObject.getJSONObject("resource");
        String ciphertext = resource.getString("ciphertext");
        String associatedData = resource.getString("associated_data");
        String nonce = resource.getString("nonce");
        return  aesUtil.decryptToString(associatedData.getBytes(StandardCharsets.UTF_8), nonce.getBytes(StandardCharsets.UTF_8), ciphertext);
    }

    private boolean verifiedSign(String serialNo, String signStr, String signature) throws UnsupportedEncodingException {
        return verifier.verify(serialNo, signStr.getBytes(StandardCharsets.UTF_8), signature);
    }

    private String getRequestBody(HttpServletRequest request) {
        StringBuffer sb = new StringBuffer();

        try (
                ServletInputStream inputStream = request.getInputStream();
                BufferedReader bufferedReader = new BufferedReader((new InputStreamReader(inputStream)));
        ) {
            String line;
            while (((line = bufferedReader.readLine()) != null)) {
                sb.append(line);
            }
        } catch (Exception e) {
            log.error("读取数据流异常{}", e);
        }

        return sb.toString();
    }
}
